/*
* Copyright (c) 2006 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_SYNCHRONIZE_H
#define M_SYNCHRONIZE_H

#ifdef WIN32
#include <windows.h> 
#else
#include <pthread.h>
#endif

namespace Engine
{	
	/**  Implements a single-threaded model; no synchronization.
	*/
	template <class MutexPolicy>
	class SingleThreaded
	{
	public:
		/** Dummy Lock class
		*/
		struct Lock
		{
			Lock() {}
			explicit Lock(const SingleThreaded&) {}
			explicit Lock(const SingleThreaded*) {}
		};
	};

    /**  Implements a object-level locking scheme.
	*/
	template <class MutexPolicy>
	class ObjectLevelLockable
	{
		/** Mutex synchronization object.
		*/
		mutable MutexPolicy mutex;
	public:
		
		/** Default constructor.
		*/
		ObjectLevelLockable() : mutex(){}
		
		/** Constructor.
		*/
		ObjectLevelLockable(const ObjectLevelLockable&) : mutex() {}
		
		/** Empty destructor.
		*/
		~ObjectLevelLockable() {}

		class Lock;
		friend class Lock;
		
		/** Class for manipulating mutex object.
		*/
		class Lock
		{
		public:

			/** Lock object
			*/
			explicit Lock(const ObjectLevelLockable& obj) : object(obj)
			{
				object.mutex.Lock();
			}

			/** Lock object
			*/
			explicit Lock(const ObjectLevelLockable* obj) : object(*obj)
			{
				object.mutex.Lock();
			}

			/** Unlock object
			*/
			~Lock()
			{
				object.mutex.Unlock();
			}

		private:
			
			/** private by design of the object level threading.
			*/
			Lock();
			
			/** private by design of the object level threading.
			*/
			Lock(const Lock&);
			
			/** private by design of the object level threading.
			*/
			Lock& operator=(const Lock&);
			
			/** Reference to synchronized object.
			*/
			const ObjectLevelLockable& object;
		};
	};

	/**  Implements a class-level locking scheme.
	*/
	template <class MutexPolicy>
	class ClassLevelLockable
	{
		/** Static mutex synchronization object.
		*/
		static MutexPolicy mutex;
	public:

		class Lock;
		friend class Lock;

		/** Class for manipulating mutex object.
		*/
		class Lock
		{
		public:
			
			/** Lock object.
			*/
			Lock()
			{
				mutex.Lock();
			}
			
			/** Lock object.
			*/
			explicit Lock(const ClassLevelLockable&)
			{
				mutex.Lock();
			}
			
			/** Lock object.
			*/
			explicit Lock(const ClassLevelLockable*)
			{
				mutex.Lock();
			}

			/** Unlock object.
			*/
			~Lock()
			{
				mutex.Unlock();
			}

		private:
			
			/** private by design of the object level threading.
			*/
			Lock(const Lock&);
			
			/** private by design of the object level threading.
			*/
			Lock& operator=(const Lock&);
		};
	};

	template <class MutexPolicy>
	MutexPolicy ClassLevelLockable< MutexPolicy >::mutex;
}

#endif
